﻿using System;
using System.Web;

namespace TSharp.Core.Caching
{
    /// <summary>
    /// Application通用操作类
    /// </summary>
    /// <author>
    /// tangjingbo
    /// </author>
    /// <remarks>
    /// tangjingbo at 2009-10-11 16:58
    /// </remarks>
    public static class ApplictionUtil
    {
        /// <summary>
        /// Gets the dic.
        /// </summary>
        private static dynamic dic
        {
            get { return AopContext.GetContext().Application; }
        }

        /// <summary>
        /// Adds the or update.
        /// </summary>
        /// <typeparam name="TValue">The type of the value.</typeparam>
        /// <param name="key">The key.</param>
        /// <param name="addValueFactory">The add value factory.</param>
        /// <param name="updateValueFactory">The update value factory.</param>
        /// <returns></returns>
        public static TValue AddOrUpdate<TValue>(string key, Func<string, TValue> addValueFactory,
                                                 Func<string, TValue, TValue> updateValueFactory)
        {
            lock (dic)
            {
                object obj = dic[key];
                if (obj == null)
                {
                    var addValue = addValueFactory(key);
                    SetValue(key, addValue, true);
                    return addValue;
                }
                else
                {
                    var oldValue = (TValue)obj;
                    var newValue = updateValueFactory(key, oldValue);
                    SetValue(key, newValue, !Equals(newValue, oldValue));
                    return newValue;
                }
            }
        }

        /// <summary>
        /// Gets the or add.
        /// </summary>
        /// <typeparam name="TValue">The type of the value.</typeparam>
        /// <param name="key">The key.</param>
        /// <param name="valueFactory">The value factory.</param>
        /// <returns></returns>
        public static TValue GetOrAdd<TValue>(string key, Func<string, TValue> valueFactory)
        {
            object obj = dic[key];
            if (obj != null)
                return (TValue)obj;
            lock (dic)
            {
                obj = dic[key];
                if (obj != null)
                    return (TValue)obj;
                TValue tv = valueFactory(key);
                SetValue(key, tv, true);
                return tv;
            }
        }


        /// <summary>
        /// Gets the specified key.
        /// </summary>
        /// <typeparam name="TValue">The type of the value.</typeparam>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        public static TValue Get<TValue>(string key)
        {
            return (TValue)dic[key];
        }

        /// <summary>
        /// Removes the specified key.
        /// </summary>
        /// <typeparam name="TValue">The type of the value.</typeparam>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        public static TValue Remove<TValue>(string key)
        {
            var value = (TValue)dic[key];
            lock (dic)
            {
                dic.Remove(key);
            }
            return value;
        }
        /// <summary>
        /// Sets the value.
        /// </summary>
        /// <typeparam name="TValue">The type of the value.</typeparam>
        /// <param name="key">The key.</param>
        /// <param name="value">The value.</param>
        /// <param name="condition">if set to <c>true</c> [condition].</param>
        private static void SetValue<TValue>(string key, TValue value, bool condition)
        {
            if (condition)
                try
                {
                    dic.UnLock();
                    dic[key] = value;
                }
                finally { dic.UnLock(); }
        }
    }
}